

#include "StringBuffer.h"

using namespace Pan;

#include <windows.h>
#include <strsafe.h>

StringBuffer::StringBuffer(unsigned long buffer_size, wchar_t *buffer) //
    : StringConst(buffer ? buffer : new wchar_t[buffer_size]),         //
      _is_out_buffer(buffer != nullptr),
      _buffer_size(buffer_size),
      _end(0)
{
    this->clear(false);
}

StringBuffer::StringBuffer(const StringBuffer &sb) //
    : StringConst(new wchar_t[sb._buffer_size]),   //
      _is_out_buffer(false),
      _buffer_size(sb._buffer_size),
      _end(sb._end)
{
    // 深复制
    unsigned long i;
    for (i = 0; i <= this->_end; ++i)
    {
        const_cast<wchar_t *>(this->_p)[i] = sb._p[i];
    }
}

StringBuffer::StringBuffer(StringBuffer &&sb)
    : StringConst(sb._p), //
      _is_out_buffer(sb._is_out_buffer),
      _buffer_size(sb._buffer_size),
      _end(sb._end)
{
    // 防止他释放内存
    sb._p = nullptr;
}

StringBuffer::~StringBuffer()
{
    // 如果是来自外部缓冲区，则不应该释放它的内存
    if (!this->_is_out_buffer)
        delete[] this->_p, this->_p = nullptr;
}

bool StringBuffer::remove_tail_char(wchar_t ch)
{

    if (this->_p[this->_end - 1] == ch)
    {
        const_cast<wchar_t *>(this->_p)[--this->_end] = L'\0';
        return true;
    }

    return false;
}

bool StringBuffer::append_tail_char(wchar_t ch)
{
    if (this->_end > 0 && this->_p[this->_end - 1] != ch)
    {
        this->append(ch);
        return true;
    }

    return false;
}

unsigned long StringBuffer::calc_length()
{

    for (this->_end = 0; this->_end < this->_buffer_size; ++this->_end)
    {
        if (this->_p[this->_end] == L'\0')
            break;
    }

    return this->_end;
}

void StringBuffer::clear(bool all)
{
    wchar_t *const wp(this->buffer());

    if (all)
    {
        // 全部置零
        for (this->_end = 0; this->_end < this->_buffer_size; ++this->_end)
        {
            wp[this->_end] = L'\0';
        }
        this->_end = 0;
    }
    else
    {
        // 仅仅将第一个字符和最后一个字符置零
        this->_end = 0;
        wp[0] = L'\0';
        wp[this->_buffer_size - 1] = L'\0';
    }
}

void StringBuffer::copy_from(const wchar_t *str)
{
    if (str == nullptr)
        return;

    wchar_t *const wp(this->buffer());

    this->_end = 0;

    while (this->buffer_size_free() > 0)
    {
        wp[this->_end] = *str;

        if (wp[this->_end] == L'\0')
            break;

        ++this->_end, ++str;
    }

    // 当str太长时确保以0结尾
    wp[this->_end] = L'\0';
}

void StringBuffer::format(const wchar_t *_format, ...)
{
    va_list vl;
    va_start(vl, _format);

    this->format2(_format, vl);

    va_end(vl);
}

void StringBuffer::format2(const wchar_t *_format, va_list va)
{
    LPWSTR endp(NULL);

    ::StringCchVPrintfExW(
        this->buffer(),
        this->buffer_size(),
        &endp,
        NULL,
        STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE,
        _format,
        va //
    );

    if (endp)
        this->_end = static_cast<unsigned long>(endp - this->_p);
    else
        this->_end = 0;
}

void StringBuffer::append(const wchar_t *str)
{

    wchar_t *const wp(this->buffer());

    while (this->buffer_size_free() > 0)
    {
        wp[this->_end] = *str;

        if (wp[this->_end] == L'\0')
            break;

        ++this->_end, ++str;
    }
    wp[this->_end] = L'\0';
}

void StringBuffer::append(const wchar_t ch)
{
    if (this->buffer_size_free() > 0)
    {
        const_cast<wchar_t *>(this->_p)[this->_end] = ch;
        const_cast<wchar_t *>(this->_p)[++this->_end] = L'\0';
    }
}
